/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.inspur.edp.web.formmetadata.event;

import com.google.common.base.Strings;
import com.inspur.edp.cdp.web.component.metadata.define.WebComponentMetadata;
import com.inspur.edp.lcm.metadata.api.entity.GspMetadata;
import com.inspur.edp.lcm.metadata.api.entity.MetadataProject;
import com.inspur.edp.web.command.component.metadata.*;
import com.inspur.edp.web.common.customexception.WebCustomException;
import com.inspur.edp.web.common.logger.WebLogger;
import com.inspur.edp.web.common.metadata.MetadataGetterParameter;
import com.inspur.edp.web.common.metadata.MetadataTypeEnum;
import com.inspur.edp.web.common.metadata.MetadataUtility;
import com.inspur.edp.web.common.utility.ResourceLocalizeUtil;
import com.inspur.edp.web.common.utility.StringUtility;
import com.inspur.edp.web.formmetadata.constant.I18nExceptionConstant;
import com.inspur.edp.web.formmetadata.constant.I18nMsgConstant;
import com.inspur.edp.web.formmetadata.metadata.formdom.FormDOM;

import java.util.*;

class WebCommandMetadataDelete {

    public List<String> generateWebCmpAndTsDeleteList(FormDOM json, MetadataProject projectInfo) {
        List<String> deleteList = new ArrayList<>();
        if (json.getModule() != null && json.getModule().getWebcmds() != null && json.getModule().getWebcmds().size() > 0) {
            HashMap<String, WebComponentMetadata> cmpList = new HashMap(8);
            HashMap<String, WebComponentMetadata> projectCmpList = new HashMap<>();
            for (HashMap<String, Object> c : json.getModule().getWebcmds()) {
                try {
                    String cmdId = c.get("id").toString();
                    WebCommandsMetadata metadata = getWebCommands(cmdId);
                    analysisComponentMetadata(metadata, cmpList, null, projectCmpList);
                    boolean hasServiceRef = analysisServiceRef(json, cmpList);
                    if (hasServiceRef) {
                        String webCmdFileName = c.get("name").toString();
                        if (StringUtility.isNullOrEmpty(webCmdFileName)) {
                            webCmdFileName = metadata.getCode() + ".webcmd";
                        }
                        if (metadata != null && metadata.getExtendProperty() != null) {
                            String refFormCode = metadata.getExtendProperty().getFormCode();
                            String currentFormCode = json.getModule().getCode();
                            if(StringUtility.isNotNullOrEmpty(currentFormCode) && currentFormCode.equals(refFormCode)){
                                deleteList.add(webCmdFileName);
                            }
                        }
                    }
                } catch (Exception ex) {
                    WebLogger.Instance.error(ex);
                }

            }
        }
        if (json != null && json.getModule() != null && json.getModule().getServiceRefs() != null && json.getModule().getServiceRefs().size() > 0) {
            List<GspMetadata> metadataList = MetadataUtility.getInstance().getMetadataListWithDesign(projectInfo.getProjectPath());
            if (metadataList == null || metadataList.size() == 0) {
                return deleteList;
            }

            for (HashMap<String, Object> o : json.getModule().getServiceRefs()) {
                if ("0".equals(o.get("isCommon").toString())) {

                    String refCmpId = o.get("cmpId").toString();


                    Optional<GspMetadata> findMetadata = metadataList.stream().filter((GspMetadata item) -> refCmpId.equals(item.getHeader().getId())
                    ).findFirst();

                    if (findMetadata.isPresent()) {
                        String fileName = findMetadata.get().getHeader().getFileName();
                        String relativeTsFileName = fileName.substring(0, fileName.lastIndexOf(".")) + ".ts";

                        if(o.get("formCode") != null){
                            String refFormCode = o.get("formCode").toString();
                            String currentFormCode = json.getModule().getCode();
                            if (StringUtility.isNotNullOrEmpty(currentFormCode) && currentFormCode.equals(refFormCode)) {
                                // 获取文件目录下所有的关联ts文件
                                deleteList.add(relativeTsFileName);

                                // 获取文件目录下所有的关联webcmp文件
                                String relativeWebCmpFileName = fileName.substring(0, fileName.lastIndexOf(".")) + ".webcmp";
                                deleteList.add(relativeWebCmpFileName);
                            }
                        }

                    }
                }
            }
        }
        return deleteList;
    }

    private void analysisComponentCommandItemList(List<CommandItem> commandItemList, HashMap<String, WebComponentMetadata> cmpList,
                                                  HashMap<String, WebComponentMetadata> projectCmpList) throws Exception {
        if (commandItemList != null && commandItemList.size() > 0) {

            WebComponentMetadata cmpMetadata = null;
            for (CommandItem item : commandItemList) {
                switch (item.getItemType()) {
                    case MethodRefer:
                        if (!cmpList.containsKey(((CmpMethodRefering) item).getComponentId())) {
                            if (!projectCmpList.containsKey(((CmpMethodRefering) item).getComponentId())) {
                                try {
                                    cmpMetadata = getComponentMetadata(((CmpMethodRefering) item).getComponentId());
                                    if (cmpMetadata != null) {
                                        cmpList.put(cmpMetadata.getId(), cmpMetadata);
                                        projectCmpList.put(cmpMetadata.getId(), cmpMetadata);
                                    }
                                } catch (Exception ex) {
                                    throw new WebCustomException(I18nExceptionConstant.WEB_FORM_METADATA_ERROR_0001, new String[]{cmpMetadata.getId()}, ex);
                                }
                            } else {
                                cmpMetadata = projectCmpList.get(((CmpMethodRefering) item).getComponentId());
                                cmpList.put(cmpMetadata.getId(), cmpMetadata);
                            }
                        }
                        break;
                    case BranchCollection:
                        analysisComponentMetadata(null, cmpList, ((BranchCollectionCommandItem) item).getItems(), projectCmpList);
                        break;
                    default:
                        break;

                }
            }
        }
    }

    private WebCommandsMetadata getWebCommands(String id) {
        MetadataGetterParameter metadataGetterParameter = MetadataGetterParameter.getNewInstance(id, null, MetadataTypeEnum.Command);
        metadataGetterParameter.setTargetMetadataNotFoundMessage(ResourceLocalizeUtil.getString(I18nMsgConstant.WEB_FORM_METADATA_MSG_0001, id));
        GspMetadata webCommandMetadata = MetadataUtility.getInstance().getMetadataWithDesign(metadataGetterParameter);
        if (webCommandMetadata == null) {
            return null;
        }
        return (WebCommandsMetadata) webCommandMetadata.getContent();
    }

    public WebComponentMetadata getComponentMetadata(String id) {
        MetadataGetterParameter metadataGetterParameter = MetadataGetterParameter.getNewInstance(id, null, MetadataTypeEnum.Component);
        metadataGetterParameter.setTargetMetadataNotFoundMessage(ResourceLocalizeUtil.getString(I18nMsgConstant.WEB_FORM_METADATA_MSG_0002, id));
        GspMetadata webComponentMetadata = MetadataUtility.getInstance().getMetadataWithDesign(metadataGetterParameter);
        if (webComponentMetadata == null) {
            throw new WebCustomException("load webComponent metadata is null,the metaDataId is " + id);
        }
        return (WebComponentMetadata) webComponentMetadata.getContent();
    }

    private void analysisComponentMetadata(WebCommandsMetadata metadata, HashMap<String, WebComponentMetadata> cmpList,
                                           List<BranchCommandItem> items,
                                           HashMap<String, WebComponentMetadata> projectCmpList) {
        if (items == null || items.size() == 0) {
            if (metadata != null && metadata.getOperations() != null && metadata.getOperations().size() > 0) {
                for (WebCommand webCommandItem : metadata.getOperations()) {
                    try {
                        analysisComponentCommandItemList(webCommandItem.getItems(), cmpList, projectCmpList);
                    } catch (Exception e) {
                        WebLogger.Instance.error(e);
                    }
                }
            }
        } else {
            for (BranchCommandItem branchCommandItem : items) {
                try {
                    analysisComponentCommandItemList(branchCommandItem.getItems(), cmpList, projectCmpList);
                } catch (Exception e) {
                    WebLogger.Instance.error(e);
                }
            }
        }
    }

    private boolean hasServiceReference(List<HashMap<String, Object>> serviceReferenceList, WebComponentMetadata component) throws Exception {
        boolean flag = false;
        for (HashMap<String, Object> serviceRef : serviceReferenceList) {
            if (serviceRef.containsKey("name") && serviceRef.containsKey("path")) {
                if (serviceRef.get("name") == null || serviceRef.get("path") == null) {
                    continue;
                }

                if (serviceRef.get("name").toString().equals(component.getClassName()) &&
                        serviceRef.get("path") == component.getSource()) {
                    flag = true;
                    break;
                }
            }
        }
        return flag;
    }

    public boolean analysisServiceRef(FormDOM json, HashMap<String, WebComponentMetadata> cmpList) throws Exception {
        boolean hasServiceRef = false;
        if (cmpList != null && cmpList.size() > 0) {
            for (Map.Entry<String, WebComponentMetadata> stringWebComponentMetadataEntry : cmpList.entrySet()) {
                HashMap.Entry entry = stringWebComponentMetadataEntry;

                HashMap<String, Object> serviceRef = new HashMap<>();
                WebComponentMetadata component = (WebComponentMetadata) entry.getValue();
                if (component == null) {
                    continue;
                }
                if (component.isCommon()) {
                    continue;
                }

                if (!component.isCommon()) {
                    hasServiceRef = true;
                }

                if (!hasServiceReference(json.getModule().getServiceRefs(), component)) {
                    serviceRef.put("cmpId", component.getId());
                    serviceRef.put("name", component.getClassName());
                    String path = component.getSource();
                    if (path == null || path.isEmpty()) {
                        path = getTSFileName(component.getId());
                        if (!Strings.isNullOrEmpty(path)) {
                            component.setSource(path);
                        }
                    }
                    serviceRef.put("path", path);

                    serviceRef.put("isCommon", component.isCommon() ? "1" : "0");
                    serviceRef.put("alias", component.getClassName() + "1");
                    serviceRef.put("formCode", component.getFormCode());

                    json.getModule().getServiceRefs().add(serviceRef);
                }
            }
        }
        return hasServiceRef;
    }


    /**
     * 获取ts文件路径和名称
     */
    private String getTSFileName(String cmpId) throws Exception {
        // 最理想的方式：路径来自webcmp构件路径，名称来自path（即元数据的Source属性）
        // 先用webcmp的文件名构造，后续可以考虑调整
        if (cmpId == null || cmpId.isEmpty()) {
            throw new WebCustomException(I18nExceptionConstant.WEB_FORM_METADATA_ERROR_0002);
        }

        MetadataGetterParameter metadataGetterParameter = MetadataGetterParameter.getNewInstance(cmpId, null, MetadataTypeEnum.TS);

        metadataGetterParameter.setTargetMetadataNotFoundMessage(ResourceLocalizeUtil.getString(I18nMsgConstant.WEB_FORM_METADATA_MSG_0003, cmpId));
        GspMetadata metadata = MetadataUtility.getInstance().getMetadataWithDesign(metadataGetterParameter);

        if (metadata != null) {
            String path = metadata.getRelativePath();
            String cmpFileName = metadata.getHeader().getFileName();
            // 后缀为.webcmp
            int suffixIndex = cmpFileName.lastIndexOf(".webcmp");
            String fileName;
            if (suffixIndex > 0 && suffixIndex + 7 == cmpFileName.length()) {
                fileName = cmpFileName.substring(0, suffixIndex);
            } else if (cmpFileName.contains(metadata.getHeader().getCode())) {
                fileName = cmpFileName;
            } else {
                throw new WebCustomException(I18nExceptionConstant.WEB_FORM_METADATA_ERROR_0003);
            }

            return path + "/" + fileName + ".ts";
        }

        return null;
    }
}
